package excelutil

import (
	"fmt"
	"reflect"
	"strconv"

	"github.com/tealeg/xlsx"
)

const (
	descTag = "desc"
)

func GetKeys(v *reflect.Value) []string {
	keys := make([]string, 0, v.NumField())
	for i := 0; i < v.NumField(); i++ {
		field := v.Type().Field(i)
		//取字段名
		name := field.Name
		keys = append(keys, name)
	}
	return keys
}

// GetColumnsByTag 获取所有的tag
func GetColumnsByTag(v *reflect.Value, tag string) []string {
	columns := make([]string, 0, v.NumField())
	for i := 0; i < v.NumField(); i++ {
		field := v.Type().Field(i)
		//取tag
		column := field.Tag.Get(tag)
		columns = append(columns, column)
	}
	return columns
}

// ReadExcelBean 返回
// []string是表头
// [][]string是表体数据
func ReadExcelBean[T any](list []T) ([]string, [][]string) {
	//根据T获取tag信息
	//获取desc
	v0 := reflect.ValueOf(list[0])
	if v0.Kind() == reflect.Ptr {
		v0 = v0.Elem()
	}
	if v0.Kind() != reflect.Struct {
		return nil, nil
	}
	columns := GetColumnsByTag(&v0, descTag)

	//for循环list将每个转成map，再塞到[][]string里
	bodyData := make([][]string, 0, len(list))
	for _, listI := range list {
		bodyDataI := make([]string, 0, v0.NumField())
		//按columns顺序将value append进来
		vI := reflect.ValueOf(listI)
		if vI.Kind() == reflect.Ptr {
			vI = vI.Elem()
		}
		//用反射来实现
		for i := 0; i < vI.NumField(); i++ {
			bodyDataI = append(bodyDataI, fmt.Sprintf("%v", vI.Field(i)))
		}

		//用json来实现
		//bytes, _ := jsonx.Marshal(&listI)
		//m := make(map[string]any)
		//_ = jsonx.Unmarshal(bytes, &m)
		//for _, key := range keys {
		//  bodyDataI = append(bodyDataI, fmt.Sprintf("%v", m[key]))
		//}
		bodyData = append(bodyData, bodyDataI)
	}
	return columns, bodyData
}

func AddHeader(sheet *xlsx.Sheet, columns []string) {
	row := sheet.AddRow()
	for _, column := range columns {
		row.AddCell().SetString(column)
	}
}

func AddBodyData(sheet *xlsx.Sheet, bodyData [][]string) {
	for i := 0; i < len(bodyData); i++ {
		addRow := sheet.AddRow()
		bodyDataI := bodyData[i]
		for j := 0; j < len(bodyDataI); j++ {
			addRow.AddCell().SetString(bodyDataI[j])
		}
	}
}

func ImportExcelByBean[T any](excel *xlsx.File) []*T {
	a := new(T)
	//获取columns
	v0 := reflect.ValueOf(a)
	if v0.Kind() == reflect.Ptr {
		v0 = v0.Elem()
	}
	if v0.Kind() != reflect.Struct {
		return nil
	}
	columns := GetColumnsByTag(&v0, descTag)
	sheet := excel.Sheets[0]
	//将第一行的name和index作为 key value
	nameMap := make(map[string]int)
	row0 := sheet.Rows[0]
	for index, cell := range row0.Cells {
		nameMap[cell.Value] = index
	}

	var res []*T
	for i := 1; i < len(sheet.Rows); i++ {
		rowI := sheet.Rows[i]
		//将每一行处理成T
		rowDto := new(T)
		rv := reflect.ValueOf(rowDto)
		if rv.Kind() == reflect.Ptr {
			rv = rv.Elem()
		}
		field := rv.NumField()
		fmt.Println(field)
		for coI, column := range columns {
			index, ok := nameMap[column]
			if !ok {
				continue
			}
			cell := rowI.Cells[index]
			//anyValue := any(cell.Value)
			//根据Field的类型先转一下Value
			fieldI := rv.Field(coI)
			var val reflect.Value
			switch fieldI.Kind() {
			case reflect.String:
				val = reflect.ValueOf(cell.Value)
			case reflect.Int:
				intVal, _ := strconv.Atoi(cell.Value)
				val = reflect.ValueOf(intVal)
			case reflect.Int64:
				int64Val, _ := strconv.ParseInt(cell.Value, 10, 64)
				val = reflect.ValueOf(int64Val)
			case reflect.Float64:
				float64Val, _ := strconv.ParseFloat(cell.Value, 64)
				val = reflect.ValueOf(float64Val)
			default:
				panic("unhandled default case")
			}
			fieldI.Set(val)
		}

		res = append(res, rowDto)
	}
	return res
}
